package org.ywf.common.ipaddress;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.lionsoul.ip2region.xdb.Searcher;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.ywf.common.entity.IpVo;
import org.ywf.common.okhttp.OkHttpUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * IP地址工具类
 *
 * @Author YWF
 * @Date 2023/2/8 16:04
 */
@Slf4j
@Component
public class IPUtil {
    private static final String UNKNOWN = "unknown";

    protected IPUtil(){ }

    /***
     * 获取客户端ip地址(可以穿透代理)
     * @param request HttpServletRequest
     * @return
     */
    public String getIp(HttpServletRequest request) {
        String ip = "";
        for (String header : HEADERS) {
            ip = request.getHeader(header);
            if(isNotEmptyIp(ip)) {
                break;
            }
        }
        if(isEmptyIp(ip)){
            ip = request.getRemoteAddr();
        }
        if(isNotEmptyIp(ip) && ip.contains(",")){
            System.out.println("ip:"+ip);
            ip = ip.split(",")[0];
        }
        if ("0:0:0:0:0:0:0:1".equals(ip)){
            ip = "127.0.0.1";
        }
        return ip;
    }

    /**
     * 获取本机的局域网ip地址，兼容Linux
     * @return String
     * @throws Exception
     */
    public String getLocalHostIP(){
        Enumeration<NetworkInterface> allNetInterfaces = null;
        String localHostAddress = "";
        try {
            allNetInterfaces = NetworkInterface.getNetworkInterfaces();
            while(allNetInterfaces.hasMoreElements()){
                NetworkInterface networkInterface = allNetInterfaces.nextElement();
                Enumeration<InetAddress> address = networkInterface.getInetAddresses();
                while(address.hasMoreElements()){
                    InetAddress inetAddress = address.nextElement();
                    if(inetAddress != null && inetAddress instanceof Inet4Address){
                        localHostAddress = inetAddress.getHostAddress();
                    }
                }
            }
        } catch (SocketException e) {
            log.error("IpUtils-->getLocalHostIP-->isError");
        }
        return localHostAddress;
    }

    /**
     * 每个 ip 数据段的 region 信息都固定了格式：国家|区域|省份|城市|ISP
     * 只有中国的数据绝大部分精确到了城市
     * 其他国家部分数据只能定位到国家，后前的选项全部是0
     *
     * @Author YWF
     * @Date  2023/2/8 17:42
     * @Param [ip]
     **/
    public String getAddr(String ip){
        String dbPath = "src/main/resources/db/ip2region.xdb";
        // 1、从 dbPath 加载整个 xdb 到内存。
        byte[] cBuff;
        try {
            cBuff = Searcher.loadContentFromFile(dbPath);
        } catch (Exception e) {
            log.info("failed to load content from `%s`: %s\n", dbPath, e);
            return null;
        }

        // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。
        Searcher searcher;
        try {
            searcher = Searcher.newWithBuffer(cBuff);
        } catch (Exception e) {
            log.info("failed to create content cached searcher: %s\n", e);
            return null;
        }
        // 3、查询
        try {
            String region = searcher.searchByStr(ip);
            return region;
        } catch (Exception e) {
            log.info("failed to search(%s): %s\n", ip, e);
        }
        return null;
    }

    /**
     * 调用太平洋网络IP地址查询Web接口（http://whois.pconline.com.cn/），返回ip、地理位置
     * {
     *             ip: "58.63.47.115",
     *             pro: "广东省",
     *             proCode: "440000",
     *             city: "广州市",
     *             cityCode: "440100",
     *             region: "天河区",
     *             regionCode: "440106",
     *             addr: "广东省广州市天河区 电信",
     *             regionNames: "",
     *             err: ""
     *         }
     */
    public static IpVo getIpVoForTPY(String ip){
        //查本机
        String url = "http://whois.pconline.com.cn/ipJson.jsp?json=true";

        //查指定ip
        if(!StringUtils.isEmpty(ip)){
            url = "http://whois.pconline.com.cn/ipJson.jsp?json=true&ip=" + ip;
        }

        StringBuilder inputLine = new StringBuilder();
        String read;
        try {
            HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
            urlConnection.setRequestProperty("Charset", "GBK");
            BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "GBK"));
            while ((read = in.readLine()) != null) {
                inputLine.append(read);
            }
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        IpVo ipVo = null;
        try {
            ObjectMapper mapper = new ObjectMapper();
            //当属性的值为空（null或者""）时，不进行序列化，可以减少数据传输
            mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
            //设置日期格式
            mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
            //转换成IpVo
            ipVo = mapper.readValue(new String(inputLine.toString().getBytes("GBK"), "GBK"), IpVo.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ipVo;
    }


    /**
     * 高德地图IP地址获取城市信息
     * @param apiUrl
     * @param ipAddress
     * @url https://restapi.amap.com/v3/ip
     * @return
     * @throws Exception
     */
    public static Map getGDIPLocationCityInfo(String apiUrl, String ipAddress) {
    	Map dataObject = new HashMap<>();
        String result = OkHttpUtils.builder()
                .url(apiUrl)
                .addParam("key", "10c42effa1449756608e52c1ddbc0528")
                .addParam("output", "JSON")
                .addParam("ip", ipAddress)
                .get()
                .sync();
        log.info("ip信息：{}",result);
        JSONObject jsonResult = (JSONObject) JSON.parse(result);
    	if(jsonResult.getInteger("status")==1){
    		String provinceID = jsonResult.containsKey("adcode")?jsonResult.getString("adcode"):"";
    		String provinceName = jsonResult.containsKey("province")?jsonResult.getString("province"):"";
    		String cityName = jsonResult.containsKey("city")?jsonResult.getString("city"):"";
    		dataObject.put("provinceID", provinceID);
    		dataObject.put("cityInfo", provinceName+":"+cityName);
    	}
    	return dataObject;
    }

    /**
     * 腾讯地图IP地址获取城市信息
     * @param apiUrl
     * @param ipAddress
     * @url https://apis.map.qq.com/ws/location/v1/ip
     * @return
     * @throws Exception
     */
    /*public static Map getTXIPLocationCityInfo(String apiUrl, String ipAddress)
            throws Exception {
        Map dataObject = new HashMap();
        StringBuffer data = new StringBuffer();
        data.append(apiUrl);
        data.append("?key=").append("SVUBZ-ZHR3O-ADQW7-S4V2Y-UQZH6-NMBLP");
        data.append("&output=").append("JSON");
        data.append("&ip=").append(ipAddress);
        JSONObject jsonResult = HttpUtils.getInstance().doGetForTxHttp(data.toString());
        if(jsonResult.getInt("status")==0){
            JSONObject resultJson = jsonResult.getJSONObject("result");
            if(resultJson!=null){
                JSONObject adInfoJson = resultJson.getJSONObject("ad_info");
                if(adInfoJson!=null){
                    String adCode = adInfoJson.has("adcode")?adInfoJson.getString("adcode"):"";
                    String provinceID = String.format("%-6s", adCode.substring(0, 2)).replace(" ", "0");
                    String cityInfo = new StringBuilder().append(adInfoJson.getString("province")).
                            append(adInfoJson.getString("city")).append(adInfoJson.getString("district")).toString();
                    dataObject.set("adCode", adCode);
                    dataObject.set("provinceID", provinceID);
                    dataObject.set("cityInfo", cityInfo);
                }
            }
        }
        return dataObject;
    }*/

    /**
     * IP地址校验信息
     **/
    private static final String[] HEADERS = {
            "X-Forwarded-For",
            "Proxy-Client-IP",
            "WL-Proxy-Client-IP",
            "HTTP_X_FORWARDED_FOR",
            "HTTP_X_FORWARDED",
            "HTTP_X_CLUSTER_CLIENT_IP",
            "HTTP_CLIENT_IP",
            "HTTP_FORWARDED_FOR",
            "HTTP_FORWARDED",
            "HTTP_VIA",
            "REMOTE_ADDR",
            "X-Real-IP"
    };

    /**
     * 判断ip是否为空，空返回true
     * @param ip
     * @return
     */
    private boolean isEmptyIp(final String ip){
        return (ip == null || ip.length() == 0 || ip.trim().equals("") || "unknown".equalsIgnoreCase(ip));
    }

    /**
     * 判断ip是否不为空，不为空返回true
     * @param ip
     * @return
     */
    private boolean isNotEmptyIp(final String ip){
        return !isEmptyIp(ip);
    }

}
